package edu.hawaii.duedates;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Formatter;
import java.util.List;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import edu.hawaii.duedates.libraries.HawaiiStateLibrary;
import edu.hawaii.duedates.libraries.LibraryBook;
import edu.hawaii.duedates.libraries.UhManoaLibrary;

/**
 * Due Date Red demonstrates simple use of httpunit to retrieve and parse a web page. Original
 * author by Philip Johnson.
 * 
 * @author Ka Hung Phillip Lau
 * @author Creighton Okada
 */
public final class DueDates {

  private static StringBuilder outputString = new StringBuilder();

  /**
   * Private constructor to silence PMD warning 'All methods are static'.
   */
  private DueDates() {
    // No code needed.
  }

  /**
   * The main class illustrates the use of this code to login in systems.
   * 
   * @param params Up to six strings: Libraries: -uhm (University of Hawaii Manoa Library) -hsl
   * (Hawaii State Library) Library Parameters: UH Manoa Library parameters: uhID, uhLastName Hawaii
   * State Library parameters: hiStateId, hiStatePassword
   * @throws Exception If problems occur accessing the library sites.
   */
  public static void main(String[] params) throws Exception {
    CommandLineArguments args = new CommandLineArguments();
    args.parseArgs(params);

    try {
      //Accessing everything through the console using within and wakeup
      if (args.usingConsole() && args.usingWakeup() && args.usingHsl() && args.usingUhm() 
          && args.usingWithin()) {
        double interval = args.getTimeInterval();
        int daysWithin = args.getDayInterval();
        String barcode = args.getBarcode();
        String pin = args.getPin();
        String uhId = args.getId();
        String lastName = args.getLastName();
        wakeupHawaiiWithin(barcode, pin, interval, daysWithin);
        wakeupUhWithin(uhId, lastName, interval, daysWithin);
      }
      //Accessing HSL using within and wakeup
      else if (args.usingConsole() && args.usingWakeup() && args.usingHsl() && args.usingWithin()) {
        double interval = args.getTimeInterval();
        int daysWithin = args.getDayInterval();
        String barcode = args.getBarcode();
        String pin = args.getPin();
        wakeupHawaiiWithin(barcode, pin, interval, daysWithin);
      }
      //Accessing UHM using within and wakeup
      else if (args.usingConsole() && args.usingWakeup() && args.usingUhm() && args.usingWithin()) {
        double interval = args.getTimeInterval();
        int daysWithin = args.getDayInterval();
        String uhId = args.getId();
        String lastName = args.getLastName();
        wakeupUhWithin(uhId, lastName, interval, daysWithin);
      }
      //Accessing HSL using wakeup
      else if (args.usingConsole() && args.usingWakeup() && args.usingHsl()) {
        double interval = args.getTimeInterval();
        String barcode = args.getBarcode();
        String pin = args.getPin();
        wakeupHawaii(barcode, pin, interval);
      }
      //Accessing UHM using wakeup
      else if (args.usingConsole() && args.usingWakeup() && args.usingUhm()) {
        double interval = args.getTimeInterval();
        String uhId = args.getId();
        String lastName = args.getLastName();
        wakeupUh(uhId, lastName, interval);
      }
      //Accessing HSL using within
      else if (args.usingConsole() && args.usingWithin() && args.usingHsl()) {
        int dayInterval = args.getDayInterval();
        String barcode = args.getBarcode();
        String pin = args.getPin();
        HawaiiStateLibrary hiInfo = new HawaiiStateLibrary();
        List<LibraryBook> books = hiInfo.getHawaiiStateInfo(barcode, pin);
        
        if (dayInterval == 0) {
          System.out.println("Returning a list of all books: ");
          outputString = formatList(books);
          System.out.println(outputString);
        }
        else {
          System.out.println("Returning a list of all books due within " + dayInterval + 
              " days: ");
          List<LibraryBook> books2 = obtainBooksWithin(books, dayInterval);
          
          if (books2.isEmpty()) {
            System.out.println("There are no books due within that time.");
          }
          else {
            outputString = formatList(books2);
            System.out.println(outputString);
          }
        }
      }  
      //Accessing UHM using within
      else if (args.usingConsole() && args.usingWithin() && args.usingUhm()) {
        int dayInterval = args.getDayInterval();
        String uhId = args.getId();
        String lastName = args.getLastName();
        UhManoaLibrary uhInfo = new UhManoaLibrary();
        List<LibraryBook> books = uhInfo.getUhInfo(uhId, lastName);
        
        if (dayInterval == 0) {
          System.out.println("Returning a list of all books: ");
          outputString = formatList(books);
          System.out.println(outputString);
        }
        else {
          System.out.println("Returning a list of all books due within " + dayInterval + 
              " days: ");
          List<LibraryBook> books2 = obtainBooksWithin(books, dayInterval);
          
          if (books2.isEmpty()) {
            System.out.println("There are no books due within that time.");
          }
          else {
            outputString = formatList(books2);
            System.out.println(outputString);
          }
        }
      }  
      //Accessing both libraries
      else if (args.usingConsole() && args.usingUhm() && args.usingHsl()) {
        String id = args.getId();
        String lastName = args.getLastName();
        UhManoaLibrary uhInfo = new UhManoaLibrary();
        List<LibraryBook> books2 = uhInfo.getUhInfo(id, lastName);
        outputString = formatList(books2);
        System.out.println(outputString);
        
        String barcode = args.getBarcode();
        String pin = args.getPin();
        HawaiiStateLibrary hiInfo = new HawaiiStateLibrary();
        List<LibraryBook> books = hiInfo.getHawaiiStateInfo(barcode, pin);
        outputString = formatList(books);
        System.out.println(outputString);
      }
      //Accessing UHM
      else if (args.usingConsole() && args.usingUhm()) {
        String id = args.getId();
        String lastName = args.getLastName();
        UhManoaLibrary uhInfo = new UhManoaLibrary();
        List<LibraryBook> books = uhInfo.getUhInfo(id, lastName);
        outputString = formatList(books);
        System.out.println(outputString);
      }
      //Accessing HSL
      else if (args.usingConsole() && args.usingHsl()) {
        String barcode = args.getBarcode();
        String pin = args.getPin();
        HawaiiStateLibrary hiInfo = new HawaiiStateLibrary();
        List<LibraryBook> books = hiInfo.getHawaiiStateInfo(barcode, pin);
        outputString = formatList(books);
        System.out.println(outputString);
      }
      else if (params[0].equals("-sort")) {
        if (params[1].equals("library")) {
          System.out.println("a");
          // sort books in alphabetical library order (Hawaii state, then UH Manoa)
        }
        else if (params[1].equals("duedate")) {
          System.out.println("b");
          // sort books in chronological due date
        }
        else if (params[1] == null) {
          System.out.println("c");
          // default to library sort
        }
        else {
          System.out.println("d");
          // error
        }
      }
      else {
        // incorrect param argument(s)
        System.out.println("Incorrect library name.  Only libraries for the University"
            + " of Hawaii at Manoa (-uhm) and Hawaii State Library (-hsl) may be entered."
            + "\nEnter either or both and provide sufficient credentials.");
      }
    }
    catch (Exception IndexOutOfBounds) {
      System.out.println("Invalid parameters entered.  \nCheck if first parameter is a valid"
          + " library and that login parameters are valid.  If two libraries were entered, "
          + "check to make sure they are accepted libraries (-uhm, -hsl) and the credentials "
          + "provided are accepted locally and are entered in the correct order"
          + "\nExample (for one library): -uhm <UH ID number> <UH ID owner's Last Name>"
          + "\nExample (for more than one library): -uhm -hsl <UH ID number> <UH ID owner's "
          + "Last Name> <HI State Library Barcode> <HI State Library Pin Number>");
    }
  }

  /**
   * Wakes up during a specified interval to access books due.
   * @param uhId user's UH ID
   * @param lastName user's last name
   * @param interval the time interval specified
   */
  private static void wakeupUh(final String uhId, final String lastName, double interval) {
    Timer timer = new Timer();
    
    TimerTask timeTask = new TimerTask() {
      public void run() {
        try {
          UhManoaLibrary uhInfo = new UhManoaLibrary();
          List<LibraryBook> books = uhInfo.getUhInfo(uhId, lastName);
          outputString = formatList(books);
          System.out.println(outputString);
        }
        catch (Exception e) {
          e.printStackTrace();
        }
      };
    };
    timer.schedule(timeTask, 0, (long) (interval * 1000 * 60 * 60 * 24 * 7));
  }

  /**
   * Wakes up during a specified interval to access books due within a number of days.
   * @param uhId user's UH ID
   * @param lastName user's last name
   * @param interval the time interval specified
   * @param daysWithin the number of days specified
   */
  private static void wakeupUhWithin(final String uhId, 
      final String lastName, double interval, final int daysWithin) {
    Timer timer = new Timer();
    
    TimerTask timeTask = new TimerTask() {
      public void run() {
        try {
          UhManoaLibrary uhInfo = new UhManoaLibrary();
          List<LibraryBook> books = uhInfo.getUhInfo(uhId, lastName);
          List<LibraryBook> books2 = obtainBooksWithin(books, daysWithin);
          outputString = formatList(books2);
          System.out.println(outputString);
        }
        catch (Exception e) {
          e.printStackTrace();
        }
      };
    };
    timer.schedule(timeTask, 0, (long) (interval * 1000 * 60 * 60 * 24 * 7));
  }
  
  /**
   * Wakes up during a specified interval to access books due within a number of days.
   * 
   * @param barcode Hawaii State Library barcode
   * @param pin Hawaii State Library PIN number
   * @param interval the time interval specified
   * @param daysWithin the number of days specified
   */
  private static void wakeupHawaiiWithin(final String barcode, final String pin, double interval,
      final int daysWithin) {
    Timer timer = new Timer();

    TimerTask timeTask = new TimerTask() {
      public void run() {
        try {
          HawaiiStateLibrary hiInfo = new HawaiiStateLibrary();
          List<LibraryBook> books = hiInfo.getHawaiiStateInfo(barcode, pin);
          List<LibraryBook> books2 = obtainBooksWithin(books, daysWithin);
          outputString = formatList(books2);
          System.out.println(outputString);
        }
        catch (Exception e) {
          e.printStackTrace();
        }
      };
    };

    timer.schedule(timeTask, 0, (long) (interval * 1000 * 60 * 60 * 24 * 7));
  }

  /**
   * Wakes up during a specified interval to access books due.
   * 
   * @param barcode Hawaii State Library barcode
   * @param pin Hawaii State Library PIN number
   * @param interval the time interval specified
   */
  private static void wakeupHawaii(final String barcode, final String pin, double interval) {
    Timer timer = new Timer();

    TimerTask timeTask = new TimerTask() {
      public void run() {
        try {
          HawaiiStateLibrary hiInfo = new HawaiiStateLibrary();
          List<LibraryBook> books = hiInfo.getHawaiiStateInfo(barcode, pin);
          outputString = formatList(books);
          System.out.println(outputString);
        }
        catch (Exception e) {
          e.printStackTrace();
        }
      };
    };

    timer.schedule(timeTask, 0, (long) (interval * 1000 * 60 * 60 * 24 * 7));
  }

  /**
   * Method that prints a list of books from within a certain number of days that they're due.
   * 
   * @param books2 full list of books
   * @param numberOfDaysWithin the number of days specified.
   * @throws Exception if login is incorrect
   * @return a list of books due within a certain date
   */
  private static List<LibraryBook> obtainBooksWithin(List<LibraryBook> books2,
      int numberOfDaysWithin) throws Exception {
    List<LibraryBook> books = new ArrayList<LibraryBook>();

    // creates a new format
    DateFormat newFormat = new SimpleDateFormat("MM/dd/yyyy", Locale.US);

    // Create a new calendar date with todays date by default
    Calendar daysLater = Calendar.getInstance();
    // change to "within" days later
    daysLater.add(Calendar.DAY_OF_MONTH, numberOfDaysWithin);

    for (int i = 0; i < books2.size(); i++) {
      Calendar fromDate = Calendar.getInstance();
      String dateToFormat = books2.get(i).toString().substring(73, 83);
      fromDate.setTime(newFormat.parse(dateToFormat));

      if (fromDate.compareTo(daysLater) < 0) {
        books.add(books2.get(i));
      }
    }

    return books;
  }

  /**
   * Builds a formatted StringBuilder for output.
   * 
   * @param list input list of books
   * @return a formatted StringBuilder
   */
  private static StringBuilder formatList(List<LibraryBook> list) {
    //clear outputString
    outputString.delete(0, outputString.length());
    Formatter formatter = new Formatter(outputString);

    formatter.format("|%-70.70s\t|%-10s|\n", "| Title", "Due Date");
    for (int i = 0; i < list.size(); i++) {
      outputString.append(list.get(i).toString());
    }

    return outputString;
  }
}
